/*
 *  RESTful DDS is a prototyping effort to demonstrate how DDS could be combined
 *  with HTTP clients, extending the realm of pub/sub distribution to true wide
 *  area networking.
 *
 *  Copyright (C) 2009 PrismTech Ltd.
 *  reinier.torenbeek@gmail.com
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License Version 3 dated 29 June 2007, as published by the
 *  Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with DDSTouchStone; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.opensplice.restful.service;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import DDS.ANY_STATUS;
import DDS.DomainParticipant;
import DDS.DomainParticipantFactory;
import DDS.DomainParticipantQosHolder;
import DDS.Duration_t;
import DDS.Subscriber;
import DDS.SubscriberQosHolder;
import DDS.Topic;

public class DDSParticipantProxy {
    
    private DomainParticipant participant;
    private String name;
    private Map<String, DDSSubscriberProxy> subscribers;
    private Map<String, DDSTopicProxy> topics;

    public DDSParticipantProxy(String _name) {
        name = _name;
        subscribers = new HashMap<String, DDSSubscriberProxy>();
        topics = new HashMap<String, DDSTopicProxy>();
        /* Create participant */
        DomainParticipantFactory dpf = DDS.DomainParticipantFactory.get_instance ();
        ErrorHandler.checkHandle(dpf, "DDS.DomainParticipantFactory.get_instance");
        DomainParticipantQosHolder dpQos = new DomainParticipantQosHolder();
          int status = dpf.get_default_participant_qos (dpQos);
          ErrorHandler.checkStatus(status, "DDS.DominParticipantFactory.get_default_participant_qos");
        participant = dpf.create_participant(null, dpQos.value, null, DDS.ANY_STATUS.value);
        ErrorHandler.checkHandle(participant, "DDS.DomainParticipantFactory.create_participant");
        dpQos = null;
    }
    
    public DDSSubscriberProxy lookupSubscriber(String partition) {
        return subscribers.get(partition);
    }
    
    public DDSSubscriberProxy lookupOrCreateSubscriber(String partition) {
        DDSSubscriberProxy result = lookupSubscriber(partition);
        if (result == null) {
            SubscriberQosHolder subQos = new SubscriberQosHolder();
            int status = participant.get_default_subscriber_qos (subQos);
            ErrorHandler.checkStatus(status, "DDS.DomainParticipant.get_default_subscriber_qos");
            subQos.value.partition.name = new String[1];
            subQos.value.partition.name[0] = partition;
            Subscriber subscriber = participant.create_subscriber(subQos.value, null, ANY_STATUS.value);    
            ErrorHandler.checkHandle(subscriber, "DDS.DomainParticipant.create_subscriber");
            subQos = null;
            result = new DDSSubscriberProxy(this, partition, subscriber);
            subscribers.put(partition, result);
        }
        return result;
    }

    public void delete() {
        int status = participant.delete_contained_entities();
        ErrorHandler.checkStatus(status, "DDS.DomainParticipant.delete_contained_entities");
        DomainParticipantFactory dpf = DDS.DomainParticipantFactory.get_instance ();
        ErrorHandler.checkHandle(dpf, "DDS.DomainParticipantFactory.get_instance");
        status = dpf.delete_participant(participant);
        ErrorHandler.checkStatus(status, "DDS.DomainParticipant.delete_participant");
    }
    
    
    public DDSTopicProxy lookupTopic(String topicName){
        return topics.get(topicName); 
    }
    
    private static final String TYPE_SUPPORT_CLASS_SUFFIX = "TypeSupport";
    private static final String GET_TYPE_NAME_METHOD = "get_type_name";
    private static final String REGISTER_TYPE_METHOD = "register_type";

    private boolean registerType(String classBaseName) {
        boolean result = true;
        
        String typeSupportName = classBaseName + TYPE_SUPPORT_CLASS_SUFFIX;
        try {
            
            Class<?> typeSupportClass = Class.forName(typeSupportName);
            Object typeSupportInstance = typeSupportClass.newInstance();
            Class<?> [] arrGetTypeNameTypeParams = {};
            Method getTypeName = typeSupportClass.getMethod(GET_TYPE_NAME_METHOD, arrGetTypeNameTypeParams);
            Object [] arrGetTypeNameParams = {};
            String usedTypeName = (String)getTypeName.invoke(typeSupportInstance, arrGetTypeNameParams);
            Class<?> [] arrRegisterTypeTypeParams = {DomainParticipant.class, String.class};
            Method registerType = typeSupportClass.getMethod(REGISTER_TYPE_METHOD, arrRegisterTypeTypeParams);
            Object [] arrRegisterTypeParams = {participant, usedTypeName };
            int status = (Integer)registerType.invoke(typeSupportInstance, arrRegisterTypeParams);
            ErrorHandler.checkStatus(status, classBaseName + ".register_type");            
        } catch (Exception e) {
            System.out.println("Could not register type " + classBaseName + ": " + e.getMessage());
            result = false;
        }
        
        return result;
    }
    
    public DDSTopicProxy lookupOrCreateTopic(String topicName, String typeName) {
        DDSTopicProxy result = lookupTopic(topicName); 
        if (result == null) {
            registerType(typeName);
            Duration_t duration = new DDS.Duration_t();
            duration.nanosec = 0;
            duration.sec = 0;
            Topic topic = participant.find_topic(topicName, duration);
            if (topic != null) {
                ErrorHandler.checkHandle(topic,"DDS.Participant.find_topic");
                result = new DDSTopicProxy(this, topicName, typeName, topic);
                topics.put(topicName, result);
            }
        }
        return result;
    }
    
    
    
    public DomainParticipant getParticipant() {
        return participant;
    }
    
    public String getName() {
        return name;
    }
}
